/* Terrain Utilities */

#include "TextureUtils.hlsl"

// Terrain Buffer
cbuffer TerrainBuffer : register(b2)
{
	float	TerrainMinHeight;
	float	TerrainMaxHeight;
	float	TerrainWidth;
	float	TerrainHeight;
};

// Displacement Texture
Texture2D<float> g_DisplacementTexture		: register(t0);
SamplerState g_DisplacementSampler			: register(s0);

/* Sample the Height Map */
float SampleHeight(float3 pos)
{
	float2 posOffset = float2(TerrainWidth / 2.0f, TerrainHeight / 2.0f);
	pos.x += posOffset.x;
	pos.z += posOffset.y;
	float2 uv = float2(0.0f, 0.0f);
	uv.x = pos.x / TerrainWidth;
	uv.y = pos.z / TerrainHeight;

	return MultiSampleTexture(g_DisplacementTexture, g_DisplacementSampler, uv, 0, float2(1.0f / TerrainWidth, 1.0f / TerrainHeight));
}

/* Calculate the Height for a Position */
float4 CalculateHeight(float4 position)
{
	float alpha = SampleHeight(position.xyz);
	float height = lerp(TerrainMinHeight, TerrainMaxHeight, alpha);

	position.y = height;

	return position;
}

// Apply the Shader to a Vertex
float3 CalculateNormal(float4 p, float2 d)
{
	float4 left = float4(p.x - d.x, p.y, p.z, p.w);
	float4 right = float4(p.x + d.x, p.y, p.z, p.w);
	float4 top = float4(p.x, p.y, p.z + d.y, p.w);
	float4 bottom = float4(p.x, p.y, p.z - d.y, p.w);

	left = CalculateHeight(left);
	right = CalculateHeight(right);
	top = CalculateHeight(top);
	bottom = CalculateHeight(bottom);

	float3 n = float3(0.0f, 0.0f, 0.0f);
	uint c = 0;

	float3 aa = normalize(left - p).xyz;
	float3 ab = normalize(bottom - p).xyz;
	n += normalize(cross(ab, aa));
	++c;

	float3 ba = normalize(bottom - p).xyz;
	float3 bb = normalize(right - p).xyz;
	n += normalize(cross(bb, ba));
	++c;

	float3 ca = normalize(right - p).xyz;
	float3 cb = normalize(top - p).xyz;
	n += normalize(cross(cb, ca));
	++c;


	float3 da = normalize(top - p).xyz;
	float3 db = normalize(left - p).xyz;
	n += normalize(cross(db, da));
	++c;

	n /= c;
	n = normalize(n);

	return n;
}